﻿Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL

Public Class HUDSurface
    Private HUD() As Single =
        {-1, -1, 0,
        -1, 1, 0,
        1, 1, 0,
        1, -1, 0}
    Private indices() As Integer =
        {0, 1, 2,
        2, 3, 0}
    Public vbo As Integer
    Public ibo As Integer
    Public vao As Integer
    Private Sub New()
        vbo = GL.GenBuffer()
        ibo = GL.GenBuffer()
    End Sub

    Private Shared self As HUDSurface
    Public Shared ReadOnly Property Singleton As HUDSurface
        Get
            If self Is Nothing Then self = New HUDSurface()
            Return self
        End Get
    End Property

    Public Sub SetupHUD()
        GL.EnableClientState(ArrayCap.VertexArray) 'vbo data declare GL2
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo)
        GL.BufferData(BufferTarget.ArrayBuffer, HUD.Length * 4, HUD, BufferUsageHint.StaticDraw)

        GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo)
        GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * 4, indices, BufferUsageHint.StaticDraw)
    End Sub

    Public Sub MakeHUD(fovy As Single, aspect As Single, viewMatrix As Matrix4, Optional znear As Single = 1.0)
        Dim halfh, halfw As Single
        halfh = Math.Tan(fovy / 2) * znear
        halfw = halfh * aspect
        Dim lt, rt, lb, rb As Vector3
        lt = New Vector3(-halfw, halfh, -znear - 0.1) REM - 0.1是为了兼容部分显卡 
        rt = New Vector3(halfw, halfh, -znear - 0.1) REM 有些显卡的OpenGL实现不包含近平面
        lb = New Vector3(-halfw, -halfh, -znear - 0.1)
        rb = New Vector3(halfw, -halfh, -znear - 0.1)

        REM Matrix4.LookAt(New Vector3(0, 0, 0), New Vector3(0, 0, -1), New Vector3(0, 1, 0)) = Matrix4.Identity
        REM View矩阵是把摄像机移动到了一个新位置，世界物体不变 View * obj
        REM 那么逆矩阵invView 则是吧 摄像机从新位置还原回去（原位置为Matrix4.Identity） invView * obj 
        REM 也可以理解obj 原位置 移动到新摄像机位置
        lt = Vector3.Transform(lt, viewMatrix.Inverted())
        rt = Vector3.Transform(rt, viewMatrix.Inverted())
        lb = Vector3.Transform(lb, viewMatrix.Inverted())
        rb = Vector3.Transform(rb, viewMatrix.Inverted())
        Dim data() As Single = {
            lb.X, lb.Y, lb.Z,
            lt.X, lt.Y, lt.Z,
            rt.X, rt.Y, rt.Z,
            rb.X, rb.Y, rb.Z
            }
        HUD = data
    End Sub

    Public Sub SetupTexture(dataTexture As Integer, texPosition As Integer, texNormal As Integer, texUVID As Integer, texTriangleVisible As Integer)
        GL.Enable(EnableCap.Texture2D)
        Dim programID = ShaderManager.Active("RayTracing")
        GL.ActiveTexture(TextureUnit.Texture0)
        GL.BindTexture(TextureTarget.TextureBuffer, dataTexture)

        GL.ActiveTexture(TextureUnit.Texture1)
        GL.BindTexture(TextureTarget.Texture2D, texPosition)
        GL.ActiveTexture(TextureUnit.Texture2)
        GL.BindTexture(TextureTarget.Texture2D, texNormal)
        GL.ActiveTexture(TextureUnit.Texture3)
        GL.BindTexture(TextureTarget.Texture2D, texUVID)
        GL.ActiveTexture(TextureUnit.Texture4)
        GL.BindTexture(TextureTarget.Texture2D, texTriangleVisible)

        Dim uTexPosition = GL.GetUniformLocation(programID, "texPosition")
        Dim uTexNormal = GL.GetUniformLocation(programID, "texNormal")
        Dim uTexID = GL.GetUniformLocation(programID, "texUVID")
        Dim utexTriangleVisible = GL.GetUniformLocation(programID, "texTriangleVisible")
        GL.Uniform1(uTexPosition, 1)
        GL.Uniform1(uTexNormal, 2)
        GL.Uniform1(uTexID, 3)
        GL.Uniform1(utexTriangleVisible, 4)
        RayTracing.sceneManager.SetupTextureHandle(programID)
    End Sub

    Public Sub Render()
#Region "Vertexbuffer Usage"
        GL.BindBuffer(BufferTarget.ArrayBuffer, vbo)
        'GL.VertexPointer(3, VertexPointerType.Float, 3 * 4, 0) 'vbo setup method GL2
        'GL.ColorPointer(3, ColorPointerType.Float, 3 * 4 * 2, 3 * 4) 'vbo setup method GL2
#End Region

#Region "Indexbuffer Usage0"
        'GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0)
        'GL.DrawElements(OpenGL.PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, indices) 'ibo draw method
#End Region
#Region "Indexbuffer Usage1"
        GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo)
        GL.EnableVertexAttribArray(0) 'only using when vao enable GL3
        GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, False, 3 * 4, 0) ' vao GL3

#End Region

#Region "Query for debug"
        GL.DrawElements(OpenGL.PrimitiveType.Triangles, indices.Length, DrawElementsType.UnsignedInt, 0) 'ibo draw method
        'Dim q = GL.GenQuery()
        'GL.BeginQuery(QueryTarget.PrimitivesGenerated, q)
        'GL.EndQuery(QueryTarget.PrimitivesGenerated)
        'Dim result As Integer
        'GL.GetQueryObject(q, GetQueryObjectParam.QueryResult, result)
        'GL.DeleteQuery(q)
        'result = 0
#End Region

    End Sub
End Class
